import esp32
import machine
import time
import sys
import uasyncio as asyncio
from machine import Pin

relay1 = Pin(8, Pin.OUT)    # create output pin on GPIO0
relay2 = Pin(11, Pin.OUT)    # create output pin on GPIO0
relay3 = Pin(6, Pin.OUT)    # create output pin on GPIO0
# relay1.off()
# relay2.off()
# relay3.off()
def   test_relay():
    for i in range(20):
        print("relay1 "+str(i))
        relay1.on()
        time.sleep_ms(1000)
        relay1.off()
        time.sleep_ms(1000)
       #print("relay2 "+str(i))
       #relay2.on()
       #time.sleep_ms(1000)
       #relay2.off()
       #time.sleep_ms(1000)
       #print("relay3 "+str(i))
       #relay3.on()
       #time.sleep_ms(1000)
       #relay3.off()
       #time.sleep_ms(1000)

    relay1.off()
    relay2.off()
    relay3.off()
def  show_info():
    print (esp32.raw_temperature()) # read the wake reason
    esp32.raw_temperature() 
def  relay_ctrl():
    # Set GPIO pin 13 as output
    log_pin = relay1# 12 for log+gnd
    pwr_pin = relay2# 13 for main power

    pwr_pin.value(1) # Turn off main power
    time.sleep(2)  # Delay
    log_pin.value(1) # Ground log
    time.sleep(1)  # Delay
    pwr_pin.value(0) # Turn on main power
    time.sleep(1)  # Delay
    print("Normal reset completed")
def handle_received_data(data):
    """Process received data from UART"""
    try:
        # Try to decode as UTF-8
        try:
            received_str = data.decode('utf-8')
            print("Handled data: {}".format(received_str.strip()))
            # Additional processing logic can be added here
            # For example, check for specific commands or patterns
            # Control relay1 based on received commands
            if 'relay1 on' in received_str.lower():
                relay1.on()
                print("Relay1 turned ON")
            elif 'relay1 off' in received_str.lower():
                relay1.off()
                print("Relay1 turned OFF")
            # Control relay2 based on received commands
            elif 'relay2 on' in received_str.lower():
                relay2.on()
                print("Relay2 turned ON")
            elif 'relay2 off' in received_str.lower():
                relay2.off()
                print("Relay2 turned OFF")
        except UnicodeError:
            # If UTF-8 decoding fails, show byte representation
            print("Handled non-UTF8 data, byte representation:", data)
    except Exception as e:
        print("Error handling data:", e)

def  com1_task():
    # Open UART1 for asynchronous data transmission and reception using asyncio
    try:
        # In MicroPython, use machine.UART to control serial port
        # Parameters:
        # UART(1) - Use UART 1
        # baudrate=115200 - Baud rate
        # tx=Pin(0) - Transmit pin
        # rx=Pin(1) - Receive pin
        # Note: Please modify pin numbers according to actual hardware connection
        uart = machine.UART(1, baudrate=115200, tx=Pin(0), rx=Pin(1))
        
        print("UART1 initialized, baudrate: 115200")
        
        # Create a data buffer for async communication
        # No lock needed in asyncio as we yield control explicitly
        data_buffer = []
        running = [True]  # Using list to allow modification in coroutines
        
        async def receive_task():
            """Coroutine for continuously receiving data from UART"""
            print("Data reception coroutine started")
            try:
                # MicroPython UART doesn't support timeout attribute after initialization
                # We'll read data directly and use asyncio.sleep for control flow
                while running[0]:
                    data = uart.read(128)  # Try to read up to 128 bytes
                    if data:
                        # In asyncio, we don't need locks since we yield control explicitly
                        data_buffer.append(data)
                        print("Received {} bytes, added to buffer".format(len(data)))
                        # Process data immediately
                        handle_received_data(data)
                    # Use asyncio.sleep instead of time.sleep to allow other coroutines to run
                    await asyncio.sleep_ms(10)  # Small delay to prevent CPU overload
            except Exception as e:
                print(f"Reception task error: {e}")
                running[0] = False
        
        async def process_task():
            """Coroutine for processing received data from buffer"""
            print("Data processing coroutine started")
            try:
                while running[0]:
                    data_to_process = None
                    
                    # Check if there's data in the buffer and get it
                    if data_buffer:
                        data_to_process = data_buffer.pop(0)
                    
                    # Process data if available
                    if data_to_process:
                        try:
                            # Convert to string and process (MicroPython decode doesn't support keyword args)
                            try:
                                received_str = data_to_process.decode('utf-8')
                                print("Processing data: {}".format(received_str.strip()))
                            except UnicodeError:
                                # If UTF-8 decoding fails, use byte representation
                                print("Received non-UTF8 data, byte representation:", data_to_process)
                            # Here you can add additional processing logic
                        except Exception as process_error:
                            print(f"Data processing error: {process_error}")
                    
                    # Use asyncio.sleep instead of time.sleep to allow other coroutines to run
                    await asyncio.sleep_ms(50)  # Small delay to prevent CPU overload
            except Exception as e:
                print(f"Processing task error: {e}")
                running[0] = False
        
        # Send test data
        test_data = "Hello from COM1 (AsyncIO Mode)\r\n"
        uart.write(test_data)
        print(f"Sent: {test_data.strip()}")
        
        # Create and run the event loop with both coroutines
        loop = asyncio.get_event_loop()
        # Add both coroutines to the event loop
        loop.create_task(receive_task())
        loop.create_task(process_task())
        
        print("Asynchronous UART communication started")
        print("Receiving and processing data in separate coroutines...")
        
        # Return the loop so it can be run from the main function
        return loop, uart
        
    except Exception as e:
        print(f"UART initialization error: {e}")
        return None, None
if __name__ == '__main__':
    # show_info()
    # relay_ctrl()
    # Start asynchronous UART communication
    loop, uart = com1_task()
    
    # Run the event loop if it was successfully created
    if loop:
        try:
            # Run the event loop forever
            loop.run_forever()
        except KeyboardInterrupt:
            print("Program terminated by user")
        finally:
            # Clean up
            if uart:
                uart.deinit()
                print("UART1 closed")
            # Cancel all tasks and close the loop
            loop.close()
            print("Event loop closed")
